/****************************************************************
** Tutorial_Arduino_IR_Receiver_Example                           
**
** Original Author:      Sammy_K
** Webpage:              www.dreamgineer.org
**  
** Project:              Dreamgineer Tutorials: Arduino
** Written On:           June 2012
** Last Updated:         June 2012
**
** An Arduino Example That Receives IR Commands, Stores The
** Pulse Widths, And Prints The Full Commands Received.
**
****************************************************************/

/****************************************************************
** Declare Variables
****************************************************************/
const int maxNumPulses = 200;      // The (Arbitrary) Maxiumum Number Of Pulses Per Command 
unsigned long timeout = 100000;    // The (Arbitrary) Timout.  This Is The Number Of Cycles To Wait Before Assuming A Command Is Complete.

// The Following Are Declared Volatile Because They Will Be Modified In An ISR
volatile unsigned long activeStartTime = 0;      // The uSec Time When A Transition To Active Occures
volatile unsigned long activeEndTime = 0;        // The uSec Time When A Transition To Idle Occures
volatile unsigned char state = 1;                // The Current State Of The Transmission 1 = Idle, 0 = Active
volatile unsigned long timeSinceLastPulse = 0;   // The Time In uSec Since The Last Active Pulse
volatile int pulseNum = 0;                       // The Number Of Pulses Recorded Since The Last Timeout
volatile unsigned long pulses[maxNumPulses][2];  // Array To Store Pulse A Command's Worth Of Pulses

/****************************************************************
** setup() - Executes Once On Boot
**
** The Setup Function Initializes The Serial Port With A Baud Rate Of 115200, Prints A Startup Message, And Creates An External Interrupt Handler.
** The External Interrupt Handler Is Attached To DIO Pin 2 And Set To Trigger On Change (Rising Or Falling Edge)
**
****************************************************************/
void setup()
{
  Serial.begin(115200);                         // Initialize Serial Port
  Serial.println("Starting...");              // Print Message To Indicate Program Is Starting  
  attachInterrupt(0, changeEventISR, CHANGE);   // Create An Change Triggered External Interrupt On Pin 2.
}

/****************************************************************
** loop() - Executes Repeatadly After setup() returns.
**
** The Loop Function Counts Until A Pulse Is Received Or The Count Reaches The Timeout Value.  When The Count Reaches The Timeout Value The Pulses 
** Array Is Printed In C Code Style, Or, If No Pule Was Received Before The Timeout, An 'Idle' Message Is Printed
**
****************************************************************/
void loop()
{
  //Print Output If No Pulse Recieved Before Timeout
  if(timeSinceLastPulse >= timeout)
  {
    // Timeout Occurred
    if(pulseNum > 0)
    {
      //Pulses Have Been Stored, Send Them To PC
      for(int i=0; i<pulseNum; i++)
      {  
        // Print Command
        Serial.print("Active = ");
        Serial.print(pulses[i][0], DEC);
        Serial.print("uSec | Idle = ");
        Serial.print(pulses[i][1], DEC);
        Serial.println("uSec");        
      }  
      Serial.println("Command Complete");
      pulseNum = 0;    // Reset Number Of Pulses Recorded To 0
    }
    else     
    {
      // Timeout, But No Pulses Recorded
      Serial.println("Idle...");  // Print Idle Message
    } 
    timeSinceLastPulse = 0;       // Reset Timeout Counter
  }
  timeSinceLastPulse++;           // Increment Timeout Counter
}


/****************************************************************
** changeEventISR()
**
** The Change Event ISR Is Triggered When A Rising Or Falling Edge Occures On Pin 2.  The Time Of The Edge Is Stored In The Appropriate 
** Variable Based On The Current State And The State Is Updated.
**
****************************************************************/
void changeEventISR()
{
  // Change Event Detected
  if(state==1) 
  {   
    // Transition To Active   
    activeStartTime = micros();                   // Record Transition To Active Time
    if(pulseNum < maxNumPulses & pulseNum > 0)    // Ignore First Idle
    {
      // Calculate Previous Idle Width And Store (Ignoring First Idle)
      pulses[pulseNum-1][1] = activeStartTime - activeEndTime;
    }    
    timeSinceLastPulse = 0;                       // Reset Time Since Last Pulse
    state = 0;                                    // Set Current State To Active
  }  
  else if(state==0)
  {
    // Transition To Idle 
    activeEndTime = micros();                     // Record Transition To Idle Time      
    if(pulseNum < maxNumPulses)                   // Make Sure There Is Room To Record The Pulse
    {
      // Calculate Active Pulse Width And Store (Providing There Is Room To Do So)
      pulses[pulseNum][0] = activeEndTime - activeStartTime;
    }
    timeSinceLastPulse = 0;                       // Reset Time Since Last Pulse
    state = 1;                                    // Set Current State To Idle
    pulseNum++;                                   // Increment The Number Of Pulses Recorded
  }
}

/****************************************************************
** Copyright (c) Dreamgineer.org
**
** Permission to use, copy, modify, and distribute this software 
** for any purpose with or without fee is hereby granted, 
** provided that the above copyright notice and this permission 
** notice appear in all copies. 
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 
** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 
** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
****************************************************************/
